import json
import math
import numpy as np
import os
#import matplotlib.pyplot as plt
#from mpl_toolkits.mplot3d import Axes3D


# 假设C#生成的JSON结构如下：
# {
#     "name": "SomeName",
#     "component": [...],
#     "kafcomponent": [...],
#     "pipes": [...],
#     "generatrixs": [...],
#     "casing": {...}
# }

#with open('D:\\606ApplicationV1.0\\run\\config\\data.json', 'r') as f:
#    data = json.load(f)

#print(data['ResolutionRatio'])
#print(data['MinPoint'])
#print(data['MaxPoint'])
#print(data['CenterPoint'])
#print(data['Path'])
# 指定文件路径
#file_path = data['Path']+'\\'+'cmps.json'
#file_path='D:\\cmps.json'
# 使用with语句打开文件并自动处理文件关闭
#with open(file_path, 'r',encoding='utf-8') as file:
#    # 使用json.load()直接从文件对象中解析JSON数据
#    cmps = json.load(file)
#print(cmps['pipeSlist'])

def Radialinterpolation(cmps, x, height):
    #插值函数，依据输入的x坐标，在cmps['generatrixs']中找到对应的y坐标并偏移给定高度
    
    x_max=cmps.generatrixs[-1].x
    x_min=cmps.generatrixs[0].x
    if x>=x_max :
        return x_max+height
    elif  x<=x_min:
        return x_min+height
    else:
        for i in range(len(cmps.generatrixs)-1):
            if cmps.generatrixs[i].x<=x and cmps.generatrixs[i+1].x>=x:
                x1=cmps.generatrixs[i].x
                x2=cmps.generatrixs[i+1].x
                y1=cmps.generatrixs[i].d
                y2=cmps.generatrixs[i+1].d
                y=(y2-y1)/(x2-x1)*(x-x1)+y1
                return y+height


def point_in_box(box_info, point):
    center = np.array(box_info.centerPoint)
    rotation_matrix = np.array(box_info.csy).reshape(3, 3)
    vertices = np.array(box_info.coordpoints)
    # 如果还没有计算过half_extents，进行计算
    if box_info.half_extents is None:
        # 计算包围盒的半轴长
        axis_0, axis_1, axis_2 = rotation_matrix.T

        half_extents = [0, 0, 0]

        for i, axis in enumerate([axis_0, axis_1, axis_2]):
            max_proj = float('-inf')
            min_proj = float('inf')

            for vertex in vertices:
                proj = np.dot(vertex - center, axis)
                max_proj = max(max_proj, proj)
                min_proj = min(min_proj, proj)

            half_extents[i] = (max_proj - min_proj) / 2

        # 存储计算结果，避免重复计算
        box_info.half_extents = half_extents

    else:
        half_extents = box_info.half_extents

    # 从中心点偏移点
    offset_point = np.array(point) - center
    #print(point,center)
    # 将点转换到局部坐标系
    local_point = np.dot(np.linalg.inv(rotation_matrix), offset_point)
    return all(abs(local_point) <= half_extents)

def getminigrid(box, gridsize,cmps):
    #print(box)
    borange=box.boxrange
    z_min=borange[0]
    theta_min=borange[1]
    z_max=borange[2]
    theta_max=borange[3]
    p_min= borange[4]
    p_max=borange[5]
    #print(gridsize)
    num_z = int((z_max - z_min) / gridsize[2])
    #print(z_max,z_min,gridsize[2],num_z)
    num_theta = int((theta_max - theta_min) / gridsize[1])
    #print(theta_max,theta_min,gridsize[1],num_theta)
    num_p = int((p_max-p_min) / gridsize[0])
    minigrid = np.zeros((num_p, num_theta,num_z),dtype=int)
    for i in range(num_p):
        for j in range(num_theta):
            mark1=-1
            mark2=-1
            theta = theta_min + (j) *gridsize[1]
            for k in range(num_z):
                z = z_min + k * gridsize[2]
                #print("z",z,z_min,k , gridsize[2],Radialinterpolation(cmps,z, 0))
                p = p_min + i * gridsize[0]+Radialinterpolation(cmps,z, 0)
                
                coord = convert_to_coord(p, theta, z)
               
                if point_in_box(box, coord):
                    #print(k)
                    mark1=k
                    break
                    #minigrid[i,j,k]=1
                #else:
                #    print(p,theta, z,coord)
                #    minigrid[i,j,k]=2
                    

            for l in  reversed(range(num_z)):
                #print("l",l)
                z = z_max - l * gridsize[2]
                p = p_min+Radialinterpolation(cmps,z, 0) + i * gridsize[0]
                coord = convert_to_coord(p, theta, z)
                if point_in_box(box, coord):
                    mark2=l
                    #print(l)
                    break
            
            if mark1==-1 or mark2==-1:
                #print(j,mark1,mark2)
                continue
            else:
                minigrid[i,j,mark1:mark2+1]=1
                

    return minigrid,(p_min,theta_min,z_min)
#画中心线
def line_tool(cmps,map,p1,p2,b,gridsize,theta_min,z_min):
    #print(map.shape)
    o,p,q=map.shape
    bb=min(b/gridsize[0],b/gridsize[2])

    exprange= range(-int(bb),int(bb))

    n_x=int((np.abs(p2[0] - p1[0])+1) / b)
    n_y=int((np.abs(p2[1] - p1[1])+1) / b)
    n_z=int((np.abs(p2[2] - p1[2])+1) / b)
    n=max(n_x,n_y,n_z)
    x=np.round(np.linspace(p1[0], p2[0], n), 0).astype(int)
    y=np.round(np.linspace(p1[1], p2[1], n), 0).astype(int)
    z=np.round(np.linspace(p1[2], p2[2], n), 0).astype(int)

    for i,j,k in zip(x,y,z):
        p_points = convert_to_cyl(i,j,k)
       
        num_z = int((p_points[2] - z_min) / gridsize[2])
        num_theta = int((p_points[1] - theta_min) / gridsize[1])
        num_p = int((p_points[0]-Radialinterpolation(cmps,p_points[2], 0)) / gridsize[0])
        #print(i,j,k,p2,type(p2))
        #print(num_p,num_theta,num_z)
        if num_p>=o or num_theta>=p or num_z>=q:
            continue
        elif num_p<0 or num_theta<0 or num_z<0:
            continue
        else:
            map[int(num_p),int(num_theta),int(num_z)]=1
        
        for dq in exprange:
            for dr in exprange:
                 map[int(num_p),int(num_theta)+ dq,int(num_z)+ dr] = 1        
    return map
def getpipeobs(cmps,map,gridsize,theta_min,z_min):
    for i in cmps.pipeSlist:
        #print(i)
        p1=i.p1
        p2=i.p2
        d=i.r
        #print(map.shape)
        map=line_tool(cmps,map, p1, p2, d,gridsize,theta_min,z_min)
        #依据分辨率将线段分成若干点
    return map

def getlocationbox(cmps,pz_max,pz_min,pt_max,pt_min):
    localsbox_list=[]
    cboxs=[]
    if cmps.kafcomponent!=None:
        cp=cmps.kafcomponent
    else:
        cp=cmps.component
    for i in cp:
        if i.name not in []:
            #print(i['name'])
            for j in i.boxlist:
                    cpoint=convert_to_cyl(j.centerPoint[0],j.centerPoint[1],j.centerPoint[2])
                    bpoints=[]
                    for cord in j.coordpoints:
                        bpoints.append(convert_to_cyl(cord[0],cord[1],cord[2]))
                    
                    z_min=min([point[2] for point in bpoints])
                    z_max=max([point[2] for point in bpoints])
                    theta_min=min([point[1] for point in bpoints])
                    theta_max=max([point[1] for point in bpoints])
                    theta_center=cpoint[1]
                    if theta_min<theta_center<theta_max:
                        borange=[z_min,theta_min,z_max,theta_max]
                    else:
                        borange=[z_min,theta_max,z_max,theta_min+2*math.pi]
                    j.boxrange=borange+[min([point[0]-Radialinterpolation(cmps,point[2], 0) for point in bpoints]),max([point[0]-Radialinterpolation(cmps,point[2], 0) for point in bpoints])]
                    
                    if z_min>pz_max or z_max<pz_min:
                        pass
                    elif borange[1]<pt_min or borange[3]>pt_max:
                        pass
                    else :
                        cboxs.append(j)
                        if borange[0]>=pz_min:
                            localsbox_list.append(borange[0])
                        else:
                            localsbox_list.append(pz_min)
                        if borange[1]>=pt_min:
                            localsbox_list.append(borange[1])
                        else:
                            localsbox_list.append(pt_min)
                        if borange[2]<=pz_max:
                            localsbox_list.append(borange[2])
                        else:
                            localsbox_list.append(pz_max)                            
                        if borange[3]<=pt_max:
                            localsbox_list.append(borange[3])
                        else:
                            localsbox_list.append(pt_max)                                                                    
    return  localsbox_list,cboxs                                                                                                                                                                                                                                                                                          
def convert_to_cyl(x,y,z):
    # 将点转换为圆柱坐标
    r = math.sqrt(y**2 + z**2)
    theta = math.atan2(z, y)
    z = x
    return (r, theta, z)

def convert_to_coord(r, theta, z):
    # 将圆柱坐标转换为笛卡尔坐标
    x = z
    y = r * math.cos(theta)
    z = r * math.sin(theta)
    return (x, y, z)
                   
def addmap(map,minimap,minipoint,dp,dt,dz,mt,mz):
    a,b,c=minimap.shape
    o,p,q=map.shape
    #print(minipoint)
    #print('a',a,'b',b,'c',c)
    #print('o',o,'p',p,'q',q)
    p1=[math.floor((minipoint[0])/dp),math.floor((minipoint[1]-mt)/dt),math.floor((minipoint[2]-mz)/dz)]
    #print('p1',math.floor((minipoint[0])/dp))
    p2=[p1[0]+a, p1[1]+b,p1[2]+c]
    #print('p1',p1,'p2',p2)
    if p2[0]<0 or p2[1]<0 or p2[2]<0 or p1[0]>o or p1[1]>p or p1[2]>q:
        return map
    big=np.zeros([6],dtype=int)
    small=np.zeros([6],dtype=int)
    if p1[0]<0:
        big[0]=0
        small[0]=-p1[0]
    else:
        big[0]=p1[0]

    if p1[1]<0:
        big[1]=0
        small[1]=-p1[1]
    else:
        big[1]=p1[1]

    if p1[2]<0:
        big[2]=0
        small[2]=-p1[2]
    else:
        big[2]=p1[2]

    if p2[0]>o:
        big[3]=o
        small[3]=a-(p2[0]-o)
    else:
        big[3]=p2[0]
        small[3]=a
    if p2[1]>p:
        big[4]=p
        small[4]=b-(p2[1]-p)
    else:
        big[4]=p2[1]
        small[4]=b
    if p2[2]>q:
        big[5]=q
        small[5]=c-(p2[2]-q)
    else:
        big[5]=p2[2]
        small[5]=c
   
    if small.any()==0:
        return map
    else:
        map[big[0]:big[3],big[1]:big[4],big[2]:big[5]]=minimap[small[0]:small[3],small[1]:small[4],small[2]:small[5]]
        return map

class grid:
    def __init__(self, resolution_ratio, minpoint, maxpoint, centerpoint,cmps):
        self.resolution_ratio = resolution_ratio
        self.minpoint = minpoint
        self.maxpoint = maxpoint
        self.centerpoint = centerpoint
        self.cmps=cmps
        self.p_min=0
        self.p_max=0
        self.theta_min=0
        self.theta_max=0
        self.z_min=0
        self.z_max=0
        

    
    def creat_grid(self,cmps):
        p1c= convert_to_cyl(self.minpoint[0],self.minpoint[1],self.minpoint[2])
        p2c= convert_to_cyl(self.maxpoint[0],self.maxpoint[1],self.maxpoint[2])
        pcc= convert_to_cyl(self.centerpoint[0],self.centerpoint[1],self.centerpoint[2])

        p_min = min(p1c[0],p2c[0],pcc[0])
        p_max = max(p1c[0],p2c[0],pcc[0])+200
        theta_min = min(p1c[1],p2c[1],pcc[1])
        theta_max = max(p1c[1],p2c[1],pcc[1])
        z_min = min(p1c[2],p2c[2],pcc[2])
        z_max = max(p1c[2],p2c[2],pcc[2])


        self.p_min=p_min
        self.p_max=p_max    
        self.theta_min=theta_min
        self.theta_max=theta_max
        self.z_min=z_min
        self.z_max=z_max
        


        if pcc[1]<theta_min or pcc[1]>theta_max:
            theta_min=theta_max
            theta_max=min(p1c[1],p2c[1],pcc[1])+2*math.pi

        #计算平均值
        d_values = [item.d for item in cmps.generatrixs]
        # 使用NumPy转换为数组
        d_array = np.array(d_values)

        # 使用NumPy计算平均数
        average_d = np.mean(d_array)

        #计算平均弧长
        average_arc_length = average_d*(theta_max - theta_min)
        num_p = math.floor((p_max - p_min) / self.resolution_ratio[0])
        num_theta = math.floor(average_arc_length / self.resolution_ratio[1])
        delta_theta= (theta_max - theta_min) / num_theta
        num_z = math.floor((z_max - z_min) / self.resolution_ratio[2])
        self.grid = np.zeros((num_p, num_theta, num_z))
        _,cboxs=getlocationbox(cmps,z_max,z_min,theta_max,theta_min)
        #print("nihao",z_max,z_min,theta_max,theta_min)
        self.delta_theta= delta_theta
        for i in cboxs:
            if i ==cboxs[1]:
                continue
            minicb, minipoint = getminigrid(i, (self.resolution_ratio[0], delta_theta, self.resolution_ratio[2]),self.cmps)
            map=addmap(self.grid,minicb, minipoint,self.resolution_ratio[0], delta_theta, self.resolution_ratio[2],theta_min,z_min)
            if map is not None:
                self.grid = map
        getpipeobs(cmps,self.grid,(self.resolution_ratio[0], delta_theta, self.resolution_ratio[2]),theta_min,z_min)    
        return self.grid
    
    def convert_to_gobalgrid(self,point):

        cc=convert_to_cyl(point[0],point[1],point[2])
        zz=round((cc[2]-self.z_min)/self.resolution_ratio[2])
        rrr=Radialinterpolation(self.cmps,cc[2],0)
        #print(cc[2],rrr)
        pp=round((cc[0]-rrr)/self.resolution_ratio[0])
        tt= round((cc[1]-self.theta_min)/self.delta_theta)                                        
        aa=(pp,tt,zz)
        
        
        return np.array(aa) 
     
    #管路膨胀
    def pipe_expand(self, radius):
        n_p=int(math.ceil(radius-self.resolution_ratio[0]/2)/self.resolution_ratio[0])
        n_t=int(math.ceil(radius-self.resolution_ratio[1]/2)/self.resolution_ratio[1])
        n_z=int(math.ceil(radius-self.resolution_ratio[2]/2)/self.resolution_ratio[2])

        npp=np.array(range(-n_p,n_p+1))
        ntt=np.array(range(-n_t,n_t+1))
        nnz=np.array(range(-n_z,n_z+1))
       
        return (npp,ntt,nnz)
    
    #栅格转笛卡尔
    def convert_grid_to_coord(self, grid_point):
        o = grid_point[0]
        p = grid_point[1]
        q = grid_point[2]

        zz=self.z_min+q*self.resolution_ratio[2]
        rr=Radialinterpolation(self.cmps,zz,0)
        tt=self.theta_min+p*self.delta_theta
        pp=rr+o*self.resolution_ratio[0]
     
        coordpoint=convert_to_coord(pp,tt,zz)

        return coordpoint



    
    



#grid1 = grid(data['ResolutionRatio'],data['MinPoint'],data['MaxPoint'],data['CenterPoint'])
#map=grid1.creat_grid(cmps)
#
## 将类实例转换为字典
#data_dict = {
#    "resolution_ratio": grid1.resolution_ratio,
#    "minpoint": grid1.minpoint,
#    "maxpoint": grid1.maxpoint,
#    "centerpoint": grid1.centerpoint,
#    "p_min": grid1.p_min,
#    "theta_min": grid1.theta_min,
#    "z_min": grid1.z_min,
#    "delta_theta":grid1.delta_theta,
#    "grid": map.tolist()
#}
#json_data = json.dumps(data_dict)
## 保存到文件
#
#f_path = os.path.join(data['Path'], "map.json")
#f_path=os.path.normpath(f_path).replace("\\", "/")
#with open(f_path, 'w') as f:
#    json.dump(data_dict, f)
#print(f_path)
## 假设你的三维张量是一个numpy数组
#tensor = map
#
#fig = plt.figure()
#ax = fig.add_subplot(111, projection='3d')
#
## 获取张量的坐标和值
#x, y, z = np.where(tensor == 1)
##l, m, n = np.where(tensor == 2)
## 在对应的位置上画点
#ax.scatter(x, y, z, c='r', marker='o', alpha=0.5)
#ax.scatter(e_array, f_array, g_array, c='c', marker='o', alpha=0.5)
#ax.scatter(0, 0, 0 , c='y', marker='o', alpha=0.5)
#ax.scatter(tensor.shape[0], tensor.shape[1], tensor.shape[2] , c='b', marker='o', alpha=0.5)
#ax.set_xlabel('X Label')
#ax.set_ylabel('Y Label')
#ax.set_zlabel('Z Label')
#
#plt.show()